/**
 * 文件上传服务
 * File Upload Service
 */

const multer = require('multer');
const path = require('path');
const fs = require('fs').promises;
const { v4: uuidv4 } = require('uuid');
const Jimp = require('jimp');
const config = require('../config/config');
const logger = require('../utils/logger');
const User = require('../database/models/User');

class FileUploadService {
  constructor() {
    this.uploadPath = config.upload.path;
    this.tempPath = config.upload.tempPath;
    this.maxFileSize = config.upload.maxFileSize;
    this.allowedTypes = {
      image: config.upload.allowedImageTypes,
      video: config.upload.allowedVideoTypes,
      audio: config.upload.allowedAudioTypes,
      document: config.upload.allowedDocumentTypes
    };
    
    // 上传进度跟踪
    this.uploadProgress = new Map(); // uploadId -> progress info
    this.uploadTimeouts = new Map(); // uploadId -> timeout handle
    
    this.initializeDirectories();
  }

  /**
   * 初始化目录结构
   */
  async initializeDirectories() {
    try {
      const directories = [
        this.uploadPath,
        this.tempPath,
        path.join(this.uploadPath, 'avatars')
      ];

      for (const dir of directories) {
        await fs.mkdir(dir, { recursive: true });
      }
    } catch (error) {
      logger.error('初始化目录失败 / Failed to initialize directories', {
        error: error.message
      });
    }
  }

  /**
   * 创建用户目录结构
   */
  async createUserDirectories(userId) {
    try {
      const userPath = path.join(this.uploadPath, userId.toString());
      const directories = [
        userPath,
        path.join(userPath, 'images'),
        path.join(userPath, 'videos'),
        path.join(userPath, 'audio'),
        path.join(userPath, 'documents'),
        path.join(userPath, 'others'),
        path.join(userPath, 'thumbnails')
      ];

      for (const dir of directories) {
        await fs.mkdir(dir, { recursive: true });
      }

      return userPath;
    } catch (error) {
      logger.error('创建用户目录失败 / Failed to create user directories', {
        userId,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 获取文件类型
   */
  getFileType(mimeType) {
    if (this.allowedTypes.image.includes(mimeType)) {
      return 'image';
    } else if (this.allowedTypes.video.includes(mimeType)) {
      return 'video';
    } else if (this.allowedTypes.audio.includes(mimeType)) {
      return 'audio';
    } else if (this.allowedTypes.document.includes(mimeType)) {
      return 'document';
    } else {
      return 'other';
    }
  }

  /**
   * 验证文件类型
   */
  validateFileType(mimeType) {
    const allAllowedTypes = [
      ...this.allowedTypes.image,
      ...this.allowedTypes.video,
      ...this.allowedTypes.audio,
      ...this.allowedTypes.document
    ];

    return allAllowedTypes.includes(mimeType);
  }

  /**
   * 验证文件大小
   */
  validateFileSize(fileSize, fileType) {
    const limits = {
      image: config.upload.maxImageSize,
      video: config.upload.maxVideoSize,
      audio: config.upload.maxAudioSize,
      document: this.maxFileSize,
      other: this.maxFileSize
    };

    return fileSize <= limits[fileType];
  }

  /**
   * 生成唯一文件名
   */
  generateUniqueFilename(originalName) {
    const ext = path.extname(originalName);
    const baseName = path.basename(originalName, ext);
    const timestamp = Date.now();
    const uuid = uuidv4().substring(0, 8);
    
    return `${baseName}_${timestamp}_${uuid}${ext}`;
  }

  /**
   * 获取文件存储路径
   */
  getStoragePath(userId, fileType, filename) {
    const userPath = path.join(this.uploadPath, userId.toString());
    const typeFolder = fileType === 'other' ? 'others' : `${fileType}s`;
    return path.join(userPath, typeFolder, filename);
  }

  /**
   * 创建缩略图
   */
  async createThumbnail(filePath, fileType) {
    if (fileType !== 'image') {
      return null;
    }

    try {
      const thumbnailDir = path.join(path.dirname(filePath), '../thumbnails');
      await fs.mkdir(thumbnailDir, { recursive: true });
      
      const filename = path.basename(filePath, path.extname(filePath));
      const thumbnailPath = path.join(thumbnailDir, `${filename}_thumb.jpg`);

      // 使用Jimp创建缩略图
      const image = await Jimp.read(filePath);
      await image
        .scaleToFit(300, 300)
        .quality(80)
        .writeAsync(thumbnailPath);

      return thumbnailPath;
    } catch (error) {
      logger.warn('创建缩略图失败 / Failed to create thumbnail', {
        filePath,
        error: error.message
      });
      return null;
    }
  }

  /**
   * 压缩图片（已禁用 - 根据用户要求不压缩图片）
   * Image compression (disabled - per user request to not compress images)
   */
  async compressImage(filePath, maxSize = config.upload.maxImageSize) {
    // 不进行压缩，直接返回原文件路径
    // No compression, return original file path directly
    logger.debug('图片压缩已禁用，保持原文件 / Image compression disabled, keeping original file', {
      filePath
    });
    
    return filePath;
  }

  /**
   * 检查用户存储空间
   */
  async checkUserStorage(userId, fileSize) {
    try {
      const storageStats = await User.getStorageStats(userId);
      
      if (storageStats.remaining < fileSize) {
        throw new Error('存储空间不足 / Insufficient storage space');
      }

      if (storageStats.isOverLimit) {
        throw new Error('存储空间已超限 / Storage space exceeded');
      }

      return true;
    } catch (error) {
      logger.error('检查用户存储空间失败 / Failed to check user storage', {
        userId,
        fileSize,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 更新用户存储使用量
   */
  async updateUserStorage(userId) {
    try {
      const userPath = path.join(this.uploadPath, userId.toString());
      const totalSize = await this.calculateDirectorySize(userPath);
      
      await User.updateStorageUsed(userId, totalSize);
      
      return totalSize;
    } catch (error) {
      logger.error('更新用户存储使用量失败 / Failed to update user storage', {
        userId,
        error: error.message
      });
      throw error;
    }
  }

  /**
   * 计算目录大小
   */
  async calculateDirectorySize(dirPath) {
    try {
      let totalSize = 0;
      
      const items = await fs.readdir(dirPath, { withFileTypes: true });
      
      for (const item of items) {
        const itemPath = path.join(dirPath, item.name);
        
        if (item.isDirectory()) {
          totalSize += await this.calculateDirectorySize(itemPath);
        } else {
          const stats = await fs.stat(itemPath);
          totalSize += stats.size;
        }
      }
      
      return totalSize;
    } catch (error) {
      if (error.code === 'ENOENT') {
        return 0; // 目录不存在，返回0
      }
      throw error;
    }
  }

  /**
   * 配置Multer中间件
   */
  configureMulter() {
    const storage = multer.diskStorage({
      destination: async (req, file, cb) => {
        try {
          const userId = req.user.id;
          await this.createUserDirectories(userId);
          
          const fileType = this.getFileType(file.mimetype);
          const userPath = path.join(this.uploadPath, userId.toString());
          const typeFolder = fileType === 'other' ? 'others' : `${fileType}s`;
          const destPath = path.join(userPath, typeFolder);
          
          cb(null, destPath);
        } catch (error) {
          cb(error);
        }
      },
      filename: (req, file, cb) => {
        const uniqueFilename = this.generateUniqueFilename(file.originalname);
        cb(null, uniqueFilename);
      }
    });

    const fileFilter = (req, file, cb) => {
      // 验证文件类型
      if (!this.validateFileType(file.mimetype)) {
        return cb(new Error(`不支持的文件类型: ${file.mimetype} / Unsupported file type: ${file.mimetype}`));
      }

      // 验证文件大小
      const fileType = this.getFileType(file.mimetype);
      if (!this.validateFileSize(file.size, fileType)) {
        return cb(new Error(`文件大小超出限制 / File size exceeds limit`));
      }

      cb(null, true);
    };

    return multer({
      storage,
      fileFilter,
      limits: {
        fileSize: this.maxFileSize,
        files: 10 // 最多同时上传10个文件
      }
    });
  }

  /**
   * 处理上传后的文件
   */
  async processUploadedFile(file, userId) {
    try {
      const fileType = this.getFileType(file.mimetype);
      
      // 检查存储空间
      await this.checkUserStorage(userId, file.size);
      
      // 创建缩略图（仅对图片）
      const thumbnailPath = await this.createThumbnail(file.path, fileType);
      
      // 更新用户存储使用量
      await this.updateUserStorage(userId);
      
      return {
        filename: file.filename,
        originalName: file.originalname,
        filePath: file.path,
        fileSize: file.size,
        mimeType: file.mimetype,
        fileType,
        thumbnailPath
      };
    } catch (error) {
      // 如果处理失败，删除已上传的文件
      try {
        await fs.unlink(file.path);
      } catch (unlinkError) {
        logger.warn('删除失败文件时出错 / Error deleting failed file', {
          filePath: file.path,
          error: unlinkError.message
        });
      }
      
      throw error;
    }
  }

  /**
   * 创建上传任务
   */
  createUploadTask(userId, files) {
    const uploadId = uuidv4();
    const totalFiles = files.length;
    const totalSize = files.reduce((sum, file) => sum + file.size, 0);
    
    const progressInfo = {
      uploadId,
      userId,
      status: 'uploading', // uploading, completed, failed, cancelled
      totalFiles,
      completedFiles: 0,
      failedFiles: 0,
      totalSize,
      uploadedSize: 0,
      startTime: new Date(),
      files: files.map(file => ({
        originalName: file.originalname,
        size: file.size,
        status: 'pending', // pending, uploading, completed, failed
        progress: 0,
        error: null
      }))
    };
    
    this.uploadProgress.set(uploadId, progressInfo);
    
    // 设置超时清理（30分钟后自动清理）
    const timeout = setTimeout(() => {
      this.cleanupUploadProgress(uploadId);
    }, 30 * 60 * 1000);
    
    this.uploadTimeouts.set(uploadId, timeout);
    
    return uploadId;
  }

  /**
   * 更新上传进度
   */
  updateUploadProgress(uploadId, fileIndex, progress, status = 'uploading', error = null) {
    const progressInfo = this.uploadProgress.get(uploadId);
    if (!progressInfo) return;
    
    if (fileIndex >= 0 && fileIndex < progressInfo.files.length) {
      progressInfo.files[fileIndex].progress = progress;
      progressInfo.files[fileIndex].status = status;
      if (error) {
        progressInfo.files[fileIndex].error = error;
      }
    }
    
    // 计算总体进度
    const completedFiles = progressInfo.files.filter(f => f.status === 'completed').length;
    const failedFiles = progressInfo.files.filter(f => f.status === 'failed').length;
    const uploadedSize = progressInfo.files
      .filter(f => f.status === 'completed')
      .reduce((sum, f) => sum + f.size, 0);
    
    progressInfo.completedFiles = completedFiles;
    progressInfo.failedFiles = failedFiles;
    progressInfo.uploadedSize = uploadedSize;
    
    // 更新整体状态
    if (completedFiles + failedFiles === progressInfo.totalFiles) {
      progressInfo.status = failedFiles === 0 ? 'completed' : 'partial';
      progressInfo.endTime = new Date();
    }
    
    this.uploadProgress.set(uploadId, progressInfo);
  }

  /**
   * 获取上传进度
   */
  getUploadProgress(uploadId, userId) {
    const progressInfo = this.uploadProgress.get(uploadId);
    
    if (!progressInfo || progressInfo.userId !== userId) {
      return null;
    }
    
    return {
      ...progressInfo,
      overallProgress: progressInfo.totalSize > 0 
        ? Math.round((progressInfo.uploadedSize / progressInfo.totalSize) * 100)
        : 0
    };
  }

  /**
   * 取消上传
   */
  cancelUpload(uploadId, userId) {
    const progressInfo = this.uploadProgress.get(uploadId);
    
    if (!progressInfo || progressInfo.userId !== userId) {
      return false;
    }
    
    if (progressInfo.status === 'completed') {
      return false; // 已完成的上传无法取消
    }
    
    progressInfo.status = 'cancelled';
    progressInfo.endTime = new Date();
    
    // 标记所有未完成的文件为已取消
    progressInfo.files.forEach(file => {
      if (file.status === 'pending' || file.status === 'uploading') {
        file.status = 'cancelled';
      }
    });
    
    this.uploadProgress.set(uploadId, progressInfo);
    
    // 清理超时定时器
    this.cleanupUploadProgress(uploadId);
    
    return true;
  }

  /**
   * 清理上传进度记录
   */
  cleanupUploadProgress(uploadId) {
    this.uploadProgress.delete(uploadId);
    
    const timeout = this.uploadTimeouts.get(uploadId);
    if (timeout) {
      clearTimeout(timeout);
      this.uploadTimeouts.delete(uploadId);
    }
  }

  /**
   * 删除文件
   */
  async deleteFile(filePath, thumbnailPath = null) {
    try {
      // 删除主文件
      await fs.unlink(filePath);
      
      // 删除缩略图
      if (thumbnailPath) {
        try {
          await fs.unlink(thumbnailPath);
        } catch (error) {
          logger.warn('删除缩略图失败 / Failed to delete thumbnail', {
            thumbnailPath,
            error: error.message
          });
        }
      }
      
      return true;
    } catch (error) {
      logger.error('删除文件失败 / Failed to delete file', {
        filePath,
        error: error.message
      });
      throw error;
    }
  }
}

// 创建全局文件上传服务实例
const fileUploadService = new FileUploadService();

module.exports = fileUploadService;